/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


import { AliasType, AnnotationType, AnyType, ArrayType, ClassType, FunctionType, GenericType, LiteralType, NumberType, PrimitiveType, TupleType, Type, UnclearReferenceType, UnionType, UnknownType } from "../../ArkAnalyzer/src";
import { JsonValue } from "./jsonValue";

/**
 * BasicType的公共属性：_identifier
 */
class BasicType {
    protected json: JsonValue = new JsonValue();

    constructor(arkType: Type){
        this.json.setIdentifier(arkType.constructor.name);
    }
    
    public getJson(): Record<string, any>{
        return this.json.getJson();
    }
}

export function parseArkType(arkType: Type): Record<string, any> {
    let type: BasicType;
    
    if(arkType instanceof LiteralType){
        type = new QLiteralType(arkType);
    }
    else if(arkType instanceof AnyType){
        type = new QAnyType(arkType);
    }
    else if(arkType instanceof UnknownType){
        type = new QUnknownType(arkType);
    }
    else if(arkType instanceof UnclearReferenceType){
        type = new QUnclearReferenceType(arkType);
    }
    else if(arkType instanceof PrimitiveType){
        type = new QPrimitiveType(arkType);
    }
    else if(arkType instanceof UnionType){
        type = new QUnionType(arkType);
    }
    else if(arkType instanceof FunctionType){
        type = new QFunctionType(arkType);
    }
    else if(arkType instanceof ClassType){
        type = new QClassType(arkType);
    }
    else if(arkType instanceof ArrayType){
        type = new QArrayType(arkType);
    }
    else if(arkType instanceof TupleType){
        type = new QTupleType(arkType);
    }
    else if(arkType instanceof AliasType){
        type = new QAliasType(arkType);
    }
    else if(arkType instanceof GenericType){
        type = new QGenericType(arkType);
    }
    else if(arkType instanceof AnnotationType){
        type = new QAnnotationType(arkType);
    }
    else{
        type = new BasicType(arkType);
    }

    return type.getJson();
}

/**
 * LiteralType的属性：literalName
 */
class QLiteralType extends BasicType{
    constructor(literalType: LiteralType) {
        super(literalType);
        this.parse(literalType);
    }
    
    private parse(literalType: LiteralType) {
        this.json.setLiteralName(literalType.getLiteralName());
    }
}

class QAnyType extends BasicType{
    constructor(anyType: AnyType) {
        super(anyType);
        this.parse(anyType);
    }
    
    private parse(anyType: AnyType) {
        this.json.setName(anyType.toString());
    }
}

class QUnknownType extends BasicType{
    constructor(unknownType: UnknownType) {
        super(unknownType);
        this.parse(unknownType);
    }
    
    private parse(unknownType: UnknownType) {
        this.json.setName(unknownType.toString());
    }
}

class QUnclearReferenceType extends BasicType{
    constructor(unclearReferenceType: UnclearReferenceType) {
        super(unclearReferenceType);
        this.parse(unclearReferenceType);
    }
    
    private parse(unclearReferenceType: UnclearReferenceType) {
        this.json.setName(unclearReferenceType.getName());
    }
}

class QPrimitiveType extends BasicType{
    constructor(primitiveType: PrimitiveType) {
        super(primitiveType);
        this.parse(primitiveType);
    }
    
    private parse(primitiveType: PrimitiveType) {
        this.json.setName(primitiveType.getName());
    }
}

class QUnionType extends BasicType{
    constructor(unionType: UnionType) {
        super(unionType);
        this.parse(unionType);
    }
    
    private parse(unionType: UnionType) {
        let types=[]
        for(const type of unionType.getTypes()){
            types.push(parseArkType(type));
        }
        this.json.setTypes(types);
        this.json.setCurrType(parseArkType(unionType.getCurrType()));
    }
}

class QFunctionType extends BasicType{
    constructor(functionType: FunctionType) {
        super(functionType);
        this.parse(functionType);
    }
    
    private parse(functionType: FunctionType) {
        this.json.setName(functionType.getMethodSignature().toString());
    }
}

class QClassType extends BasicType{
    constructor(classType: ClassType) {
        super(classType);
        this.parse(classType);
    }
    
    private parse(classType: ClassType) {
        this.json.setName(classType.getClassSignature().toString());
    }
}

class QArrayType extends BasicType{
    constructor(arrayType: ArrayType) {
        super(arrayType);
        this.parse(arrayType);
    }
    
    private parse(arrayType: ArrayType) {
        this.json.setBaseType(parseArkType(arrayType.getBaseType()));
        this.json.setDimension(arrayType.getDimension());
    }
}

class QTupleType extends BasicType{
    constructor(tupleType: TupleType) {
        super(tupleType);
        this.parse(tupleType);
    }
    
    private parse(tupleType: TupleType) {
        let types = []
        for(const type of tupleType.getTypes()){
            types.push(parseArkType(type))
        }
        this.json.setTypes(types);
    }
}

class QAliasType extends BasicType{
    constructor(aliasType: AliasType) {
        super(aliasType);
        this.parse(aliasType);
    }
    
    private parse(aliasType: AliasType) {
        this.json.setOriginalType(parseArkType(aliasType.getOriginalType()));
        this.json.setName(aliasType.getName());
    }
}

class QGenericType extends BasicType{
    constructor(genericType: GenericType) {
        super(genericType);
        this.parse(genericType);
    }
    
    private parse(genericType: GenericType) {
        this.json.setName(genericType.getName());
    }
}

class QAnnotationType extends BasicType{
    constructor(annotationType: AnnotationType) {
        super(annotationType);
        this.parse(annotationType);
    }
    
    private parse(annotationType: AnnotationType) {
        this.json.setOriginType(annotationType.getOriginType());
    }
}
